package com.icow.wms.basic.utils;

import com.alibaba.fastjson.JSON;
import com.icow.wms.basic.domain.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.Cache;

import java.time.Instant;
import java.util.Arrays;
import java.util.List;

@Slf4j
public class OpenTcs {

    public static final String baseUrl = "http://localhost:55200/v1/";

    public static boolean markVehicleType(String name, VehicleAllowedOrderTypesTO vehicleAllowedOrderTypesTO) {
        try {
            String result = HttpClientUtils.sendPut(baseUrl + "vehicles/" + name + "/allowedOrderTypes", JSON.toJSONString(vehicleAllowedOrderTypesTO));
            if (result != null && result.startsWith("[")) {
                log.info(result);
                return false;
            }
        } catch (Exception e) {
            log.info(name + "markVehicleType error " + e.getMessage());
            return false;
        }
        return true;
    }

    public static String createTransportOrder(String name, String preJob, int priority, String start, String end, Cache locMapCache, String orderType) {
        try {
            TransportOrderCreationTO transportOrderCreationTO = new TransportOrderCreationTO();
            LocationMap locationMapStart = locMapCache.get(start, LocationMap.class);
            LocationMap locationMapEnd = locMapCache.get(end, LocationMap.class);
            if (locationMapStart == null || locationMapEnd == null) {
                return start + " 或 " + end + " 外部站点不匹配";
            }
            transportOrderCreationTO.setType(orderType);
            List<Destination> destinations = Arrays.asList(
                    new Destination(locationMapStart.getInnerLocation(), "NOP"),
                    new Destination(locationMapStart.getInnerLocation(), "Load cargo:" + locationMapStart.getInnerCargo()),
                    new Destination(locationMapEnd.getInnerLocation(), "NOP"),
                    new Destination(locationMapEnd.getInnerLocation(), "Unload cargo:" + locationMapEnd.getInnerCargo()));
            transportOrderCreationTO.setDestinations(destinations);
            if (priority != 0) {
                priority = 24 - priority;
                transportOrderCreationTO.setDeadline(Instant.now().plusSeconds(priority * 60 * 60));
            }
            if (preJob != null && !"".equals(preJob)) {
                transportOrderCreationTO.setDependencies(Arrays.asList(preJob));
            }
            String transportOrderJson = JSON.toJSONString(transportOrderCreationTO);
            String result = HttpClientUtils.sendPost(baseUrl + "transportOrders/" + name, transportOrderJson);
            if (result != null && result.startsWith("[")) {
                return result.replace("[", "").replace("]", "").trim();
            }
        } catch (Exception e) {
            log.info("createTransportOrder error " + e.getMessage());
            return e.getMessage();
        }
        return "true";
    }

    public static String createTransportOrder(String name, String type, TransportOrderCreationTO transportOrderCreationTO, Cache locMapCache) {
        try {
            transportOrderCreationTO.setType(type);
            Destination startDestination = transportOrderCreationTO.getDestinations().get(0);
            Destination endDestination = transportOrderCreationTO.getDestinations().get(1);

            LocationMap locationMapStart = locMapCache.get(startDestination.getLocationName(), LocationMap.class);
            LocationMap locationMapEnd = locMapCache.get(endDestination.getLocationName(), LocationMap.class);

            if (locationMapStart == null || locationMapEnd == null) {
                log.info(locationMapStart + " 或 " + locationMapEnd + " 外部站点不匹配");
                return locationMapStart + " 或 " + locationMapEnd + " 外部站点不匹配";
            }

            startDestination.setLocationName(locationMapStart.getInnerLocation());
            startDestination.setOperation(locationMapStart.getInnerCargo());

            endDestination.setLocationName(locationMapEnd.getInnerLocation());
            endDestination.setOperation(locationMapEnd.getInnerCargo());

            transportOrderCreationTO.setDestinations(Arrays.asList(startDestination, endDestination));
            String transportOrderJson = JSON.toJSONString(transportOrderCreationTO);
            String result = HttpClientUtils.sendPost(baseUrl + "transportOrders/" + name, transportOrderJson);
            if (result != null && result.startsWith("[")) {
                return result.replace("[", "").replace("]", "").trim();
            }
        } catch (Exception e) {
            log.info("createTransportOrder error " + e.getMessage());
            return e.getMessage();
        }
        return "true";
    }

    public static boolean markVehicleIntegrationLevel(String agvName, String integrationLevel) {
        try {
            String result = HttpClientUtils.sendPut(baseUrl + "vehicles/" + agvName + "/integrationLevel?newValue=" + integrationLevel, "");
            if (result != null && result.startsWith("[")) {
                log.info(result);
                return false;
            }
        } catch (Exception e) {
            log.info(agvName + "markVehicleIntegrationLevel error " + e.getMessage());
            return false;
        }
        return true;
    }

    public static boolean markOrderSequenceComplete(String name) {
        try {
            String result = HttpClientUtils.sendPut(baseUrl + "orderSequences/" + name + "/complete", "");
            if (result != null && result.startsWith("[")) {
                log.info(result);
                return false;
            }
        } catch (Exception e) {
            log.info(name + "markOrderSequence error " + e.getMessage());
            return false;
        }
        return true;
    }

    public static String createOrderSequence(String name, OrderSequenceCreationTO orderSequenceCreationTO) {
        try {
            String orderSequenceJson = JSON.toJSONString(orderSequenceCreationTO);
            String result = HttpClientUtils.sendPost(baseUrl + "orderSequences/" + name, orderSequenceJson);
            if (result != null && result.startsWith("[")) {
                return result.replace("[", "").replace("]", "").trim();
            }
        } catch (Exception e) {
            log.info("createOrderSequence error " + e.getMessage());
        }
        return "true";
    }

    public static boolean cancelTransportOrder(String name) {
        try {
            TransportOrder transportOrder = getTransportOrder(name);
            if (transportOrder == null) {
                log.info(name + " transportOrder is null");
                return false;
            }
            if (isCancel(transportOrder)) {
                log.info(name + " transportOrder is cancel");
                return false;
            }
            if (isFinish(transportOrder)) {
                log.info(name + " transportOrder is finish");
                return false;
            }
            HttpClientUtils.sendPost(baseUrl + "transportOrders/" + name + "/withdrawal", "");
        } catch (Exception e) {
            log.info("cancelTask error " + e.getMessage());
            return false;
        }
        return true;
    }

    public List<OrderSequence> getOrderSequences() {
        try {
            String orderSequencesJson = HttpClientUtils.sendGet(baseUrl + "orderSequences");
            List<OrderSequence> orderSequences = JSON.parseArray(orderSequencesJson, OrderSequence.class);
            return orderSequences;
        } catch (Exception e) {
            log.info("getOrderSequences error " + e.getMessage());
        }
        return null;
    }

    public OrderSequence getOrderSequenceByVehicle(String name) {
        List<OrderSequence> orderSequences = getOrderSequences();
        if (orderSequences == null || orderSequences.size() == 0) {
            return null;
        }
        for (OrderSequence orderSequence : orderSequences) {
            if (orderSequence.getProcessingVehicle() != null && orderSequence.getProcessingVehicle().equals(name)
                    && !orderSequence.isComplete() && !orderSequence.isFinished()) {
                return orderSequence;
            }
        }
        log.info(name + " no orderSequence");
        return null;
    }

    public OrderSequence getOrderSequence(String name) {
        try {
            String orderSequenceJson = HttpClientUtils.sendGet(baseUrl + "orderSequences/" + name);
            OrderSequence orderSequence = JSON.parseObject(orderSequenceJson, OrderSequence.class);
            return orderSequence;
        } catch (Exception e) {
            log.info("getOrderSequence error " + e.getMessage());
        }
        return null;
    }


    public static List<Vehicle> getVehicles() {
        try {
            String vehiclesJson = HttpClientUtils.sendGet(baseUrl + "vehicles");
            List<Vehicle> vehicles = JSON.parseArray(vehiclesJson, Vehicle.class);
            return vehicles;
        } catch (Exception e) {
            log.info("getVehicles error " + e.getMessage());
        }
        return null;
    }

    public static Vehicle getVehicle(String name) {
        try {
            String vehicleJson = HttpClientUtils.sendGet(baseUrl + "vehicles/" + name);
            Vehicle vehicle = JSON.parseObject(vehicleJson, Vehicle.class);
            return vehicle;
        } catch (Exception e) {
            log.info("getVehicle error " + e.getMessage());
        }
        return null;
    }

    public static String getVehiclePosition(String name) {
        Vehicle vehicle = getVehicle(name);
        if (vehicle != null) {
            return vehicle.getCurrentPosition();
        }
        return null;
    }

    public static TransportOrder getTransportOrder(String name) {
        try {
            String transportOrderJson = HttpClientUtils.sendGet(baseUrl + "transportOrders/" + name);
            TransportOrder transportOrder = JSON.parseObject(transportOrderJson, TransportOrder.class);
            return transportOrder;
        } catch (Exception e) {
            log.info("getTransportOrder error " + e.getMessage());
        }
        return null;
    }

    public static String getLoadLocation(TransportOrder transportOrder) {
        if (transportOrder != null &&
                transportOrder.getDestinations().size() >= 1 &&
                transportOrder.getDestinations().get(0).getOperation().startsWith("Load")) {
            return transportOrder.getDestinations().get(0).getLocationName();
        } else if (transportOrder != null &&
                transportOrder.getDestinations().size() >= 2 &&
                transportOrder.getDestinations().get(1).getOperation().startsWith("Load")) {
            return transportOrder.getDestinations().get(1).getLocationName();
        }
        return null;

    }

    public static String getUnloadLocation(TransportOrder transportOrder) {
        if (transportOrder != null &&
                transportOrder.getDestinations().size() >= 2 &&
                transportOrder.getDestinations().get(1).getOperation().startsWith("Unload")) {
            return transportOrder.getDestinations().get(1).getLocationName();
        } else if (transportOrder != null &&
                transportOrder.getDestinations().size() >= 4 &&
                transportOrder.getDestinations().get(3).getOperation().startsWith("Unload")) {
            return transportOrder.getDestinations().get(3).getLocationName();
        }
        return null;
    }

    public static boolean isBegin(TransportOrder transportOrder) {
        return transportOrder != null && transportOrder.getState().equals(OrderState.BEING_PROCESSED);
    }

    public static boolean isUnloadFinish(TransportOrder transportOrder) {
        return (transportOrder != null &&
                transportOrder.getDestinations().size() >= 2 &&
                transportOrder.getDestinations().get(1).getOperation().startsWith("Unload") &&
                transportOrder.getDestinations().get(1).getState().equals(OrderState.FINISHED)) ||
                (transportOrder != null &&
                        transportOrder.getDestinations().size() >= 4 &&
                        transportOrder.getDestinations().get(3).getOperation().startsWith("Unload") &&
                        transportOrder.getDestinations().get(3).getState().equals(OrderState.FINISHED));
    }

    public static boolean isLoadFinish(TransportOrder transportOrder) {
        return (transportOrder != null &&
                transportOrder.getDestinations().size() >= 1 &&
                transportOrder.getDestinations().get(0).getOperation().startsWith("Load") &&
                transportOrder.getDestinations().get(0).getState().equals(OrderState.FINISHED)) ||
                (transportOrder != null &&
                        transportOrder.getDestinations().size() >= 2 &&
                        transportOrder.getDestinations().get(1).getOperation().startsWith("Load") &&
                        transportOrder.getDestinations().get(1).getState().equals(OrderState.FINISHED));
    }

    public static boolean isFinish(TransportOrder transportOrder) {
        return transportOrder != null && transportOrder.getState().equals(OrderState.FINISHED);
    }

    public static boolean isCancel(TransportOrder transportOrder) {
        return transportOrder != null && transportOrder.getState().equals(OrderState.FAILED);
    }

    public static String getError1(Vehicle vehicle) {
        KeyAndValue properties = vehicle.getProperties();
        String error1 = properties.getError1();
        return error1 == null ? "0" : error1;
    }

    public static String getError2(Vehicle vehicle) {
        KeyAndValue properties = vehicle.getProperties();
        String error2 = properties.getError2();
        return error2 == null ? "0" : error2;
    }

    public static String getError(String errorOne, String errorTwo) {
        int error1 = Integer.parseInt(errorOne);
        int error2 = Integer.parseInt(errorTwo);
        if ((error1 & 0x00000001) > 0) {
            return "执行指令时出错";
        } else if ((error1 & 0x00000002) > 0) {
            return "导航角度偏差";
        } else if ((error1 & 0x00000004) > 0) {
            return "横向控制器偏差";
        } else if ((error1 & 0x00000008) > 0) {
            return "纵向控制器偏差";
        } else if ((error1 & 0x00000010) > 0) {
            return "正向转向控制器偏差";
        } else if ((error1 & 0x00000020) > 0) {
            return "反向转向控制器偏差";
        } else if ((error1 & 0x00000200) > 0) {
            return "速度或加速度值过大";
        } else if ((error1 & 0x00000400) > 0) {
            return "内存检查错误";
        } else if ((error1 & 0x00000800) > 0) {
            return "任务时间错误";
        } else if ((error1 & 0x00001000) > 0) {
            return "非法的指令号";
        } else if ((error1 & 0x00002000) > 0) {
            return "部分指令缓冲区空";
        } else if ((error1 & 0x00004000) > 0) {
            return "指令缓冲区溢出";
        } else if ((error1 & 0x00008000) > 0) {
            return "非法块结束号";
        } else if ((error2 & 0x00000001) > 0) {
            return "指令序列溢出";
        } else if ((error2 & 0x00000002) > 0) {
            return "急停按钮触发";
        } else if ((error2 & 0x00000004) > 0) {
            return "直行或转向驱动器报错";
        } else if ((error2 & 0x00000008) > 0) {
            return "熔断器故障";
        } else if ((error2 & 0x00000010) > 0) {
            return "驱动器报错";
        } else if ((error2 & 0x00000020) > 0) {
            return "安全传感器触发";
        } else if ((error2 & 0x00000040) > 0) {
            return "执行指令时报错";
        } else if ((error2 & 0x00000080) > 0) {
            return "路线生成时出错";
        } else if ((error2 & 0x00000100) > 0) {
            return "激光扫描仪无测量数据";
        } else if ((error2 & 0x00000200) > 0) {
            return "无足够的测量数据";
        } else if ((error2 & 0x00000400) > 0) {
            return "检测到标签数量小于3";
        } else if ((error2 & 0x00000800) > 0) {
            return "少于三个标签被分配";
        } else if ((error2 & 0x00001000) > 0) {
            return "标签配置不可用";
        } else if ((error2 & 0x00002000) > 0) {
            return "初始化错误";
        } else if ((error2 & 0x00004000) > 0) {
            return "PLC和导航控制器通讯错误";
        } else if ((error2 & 0x00008000) > 0) {
            return "主接触器断开";
        }
        return "其它错误";
    }

}
